//
// itertool - a polynormial and type-safe iterator framework in C++.
//
// Copyright (c) 2021-2025 Feng Cong
//
// Distributed under the MIT Software License
// See accompanying file LICENSE.txt or copy at
// https://opensource.org/licenses/MIT

#include <itertool/iter/repeat.h>

#include <algorithm>
#include <iterator>
#include <string>
#include <vector>

#include "itertool_test.h"

TEST_SUITE("Repeat") {
  TEST_CASE("RepeatIterable for finite times") {
    const int N = 4;
    const int kValue = 10;

    auto it = itertool::Repeat(kValue, N);
    SUBCASE("It should yield unchanged value") {
      while (it.HasNext()) {
        CHECK_EQ(kValue, it.GetNow());
        it.Advance();
      }
    }
    SUBCASE("Its properties should be correct") {
      CHECK(it.IsFinite());
      CHECK(it.IsResetable());
      CHECK_EQ(it.LengthHint(), N);
    }
    SUBCASE("It should run for given times") {
      int i = 0;
      while (it.HasNext()) {
        i++;
        it.Advance();
      }
      CHECK_EQ(N, i);
    }
    SUBCASE("It can be reset") {
      while (it.HasNext()) {
        it.Advance();
      }
      it.Reset();
      int i = 0;
      while (it.HasNext()) {
        i++;
        it.Advance();
      }
      CHECK_EQ(N, i);
    }

    SUBCASE("It should work for range-based loop") {
      const auto kString = std::string("Do not reply");
      for (auto str : itertool::Repeat(kString, 3)) {
        CHECK_EQ(str, kString);
      }
    }

    SUBCASE("It should work with stl algorithm routines") {
      std::vector<int> vi;
      auto it = itertool::Repeat(10, 20);
      std::copy(it.begin(), it.end(), std::back_inserter(vi));
      CHECK_EQ(vi.size(), 20);
      bool rv =
          std::all_of(vi.begin(), vi.end(), [](int val) { return val == 10; });
      CHECK(rv);
    }
  }

  TEST_CASE("Repeat for infinite times") {
    const std::string kValue("Hello");
    auto it = itertool::Repeat(kValue);
    CHECK_FALSE(it.IsFinite());
    CHECK(it.HasNext());
    CHECK_EQ(it.GetNow(), kValue);
    CHECK(it.IsResetable());
    it.Reset();
    CHECK_EQ(it.GetNow(), kValue);
    CHECK_EQ(it.LengthHint(), 0);
  }

#if 0
  TEST_CASE("For non-copy-constructible T, there should be compiler error") {
    struct SomeType {
      SomeType(const SomeType&) = delete;
      SomeType() = default;
    };
    itertool::Repeat(SomeType());
  }
#endif

}
